react hook 16.8.0
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
为什么使用hook?
    ①class 不能很好的压缩，并且会使热重载出现不稳定的情况。Hook 使你在非 class 的情况下
    可以使用更多的 React 特性。
    ②React 需要为共享状态逻辑提供更好的原生途径
    ③要解决 class 中生命周期函数经常包含不相关的逻辑，但又把相关逻辑分离到了几个不同方法中的问题

hook使用规则：
    ①不使用 class 也能使用 React
    ②hook向下兼容
    ③Hook 在 class 内部是不起作用的。但你可以使用它们来取代class 。
    ④只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。（ 就是自定义的 Hook 中也可以调用）
    ⑤只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用


提供了哪些hook？
    ①useState：返回一个 state，以及更新 state 的函数
    作用:让我们在 React 函数组件上添加内部 state
    Hook 是能让你在函数组件中“钩入” React 特性的函数。
    
    ②useEffect:可以让你在函数组件中执行副作用操作
    副作用：数据获取、设置订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”，或者简称为“作用”。
    两种常见的副作用：
    ①需要清除的 --> componentDidMount、componentWillUnmount //设置订阅取消订阅
    注释：用生命周期函数迫使我们拆分这些逻辑代码，即使这两部分代码都作用于相同的副作用。
    如果你的 effect 返回一个函数，React 将会在执行清除操作时调用它。
    ②不需要清除的 --> componentDidMount、componentDidUpdate  //修改dom

    useEffect 做了什么？
        ①它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 
        具有相同的用途，只不过被合并成了一个 API。
        ②useEffect：每次渲染后执行，不用再去考虑“挂载”还是“更新。
        ③放在组件内部调用可以访问到组件的 props 和 state。保存在函数作用域中。Hook 使用了 JavaScript 的闭包机制
        作用：使用 Hook，你可以把组件内相关的副作用组织在一起（例如创建订阅及取消订阅），而不要把
        它们拆分到不同的生命周期函数里。

        总结：每次我们重新渲染，都会生成新的 effect，替换掉之前的。每个 effect “属于”一次特定的渲染。
    注意：useEffect 会在浏览器绘制后延迟执行，但会保证在任何新的渲染前执行。React 将在组件更新前刷新
    上一轮渲染的 effect。
    useLayoutEffect：
    在浏览器执行绘制之前，useLayoutEffect 内部的更新计划将被同步刷新。


    React 何时清除 effect？ 
    React 会在组件卸载的时候执行清除操作。effect 在每次渲染的时候都会执行。这就是为什么 React 
    会在执行当前 effect 之前对上一个 effect 进行清除。

    effecthook优点：
    ①将不相关逻辑分离到不同的 effect 中，将相关的逻辑放到同一个 effect中
    ②避免了在 class 组件中因为没有处理更新逻辑而导致常见的 bug。
    注释：而 Effect每次更新的时候都要运行。并不需要特定的代码来处理更新逻辑，因为 useEffect 默认就会处理。
    它会在调用一个新的 effect 之前对前一个 effect 进行清理。
    ③通过传递第二个数组参数，对比前一次渲染的值和这次渲染的值，来跳过 Effect 进行性能优化


    自定义hook:
        特点：
        ①自定义 Hook 是一个函数，其名称以 “use” 开头，函数内部可以调用其他的 Hook
        ②自定义 Hook 是一种自然遵循 Hook 设计的约定，而并不是 React 的特性
        ③在两个组件中使用相同的 Hook 不会共享 state 和effect
        ④每次调用 Hook，它都会获取独立的 state
        命名规范：
        如果函数的名字以 “use” 开头并调用其他 Hook，我们就说这是一个自定义 Hook。 useSomething 的
        命名约定可以让我们的 linter 插件在使用 Hook 的代码中找到 bug。

        应用场景：
        如表单处理、动画、订阅声明、计时器

    其他hook:
    ①useContext 让你不使用组件嵌套就可以订阅 React 的 Context。

    ②useReducer 可以让你通过 reducer 来管理组件本地的复杂 state
   
    ①定义一个reducer
    function todosReducer(state, action) {
        switch (action.type) {
          case 'add':
            return [...state, {
              text: action.text,
              completed: false
            }];
          // ... other actions ...
          default:
            return state;
        }
      }
      ②接收一个reducer和一个初始化的state,创建一个useReducer 的 Hook
      function useReducer(reducer, initialState) {
          
        const [state, setState] = useState(initialState);
      
        function dispatch(action) {
          const nextState = reducer(state, action);
          setState(nextState);
        }
      
        return [state, dispatch];
      }
      ③在组件中使用它，让 reducer 驱动它管理 state
      function Todos() {
        const [todos, dispatch] = useReducer(todosReducer, []);
      
        function handleAddClick(text) {
          dispatch({ type: 'add', text });
        }
      
        // ...
      }
      ③useCallback
      把内联回调函数及依赖项数组作为参数传入 useCallback，它将返回该回调函数的 memoized 版本
      ④useMemo
      把“创建”函数和依赖项数组作为参数传入 useMemo，它仅会在某个依赖项改变时才重新计算 
      memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
      ⑤useImperativeHandle
      在使用 ref 时自定义暴露给父组件的实例值
      ⑥useRef 返回一个可变的 ref 对象
      

React 是如何把对 Hook 的调用和组件联系起来的？
    React 保持对当先渲染中的组件的追踪。多亏了 Hook 规范，我们得知 Hook 只会在 React 组件
    中被调用（或自定义 Hook —— 同样只会在 React 组件中被调用）。
    
    每个组件内部都有一个「记忆单元格」列表。它们只不过是我们用来存储一些数据的 JavaScript 对象。
    当你用 useState() 调用一个 Hook 的时候，它会读取当前的单元格（或在首次渲染时将其初始化），
    然后把指针移动到下一个。这就是多个 useState() 调用会得到各自独立的本地 state 的原因。
    
Hook 能否覆盖 class 的所有使用场景？
我们给 Hook 设定的目标是尽早覆盖 class 的所有使用场景。目前暂时还没有对应不常用的 
getSnapshotBeforeUpdate 和 componentDidCatch 生命周期的 Hook 等价写法，但我们计划尽早把它们加进来。

Hook 会替代 render props 和高阶组件吗？
通常，render props 和高阶组件只渲染一个子节点。我们认为让 Hook 来服务这个使用场景更加简单。这两种模式
仍有用武之地，（例如，一个虚拟滚动条组件或许会有一个 renderItem 属性，或是一个可见的容器组件或许会有它
自己的 DOM 结构）。但在大部分场景下，Hook 足够了，并且能够帮助减少嵌套。

生命周期方法要如何对应到 Hook？
①constructor：函数组件不需要构造函数。你可以通过调用 useState 来初始化 state。
如果计算的代价比较昂贵，你可以传一个函数给 useState。
②getDerivedStateFromProps：改为 在渲染时 安排一次更新。
③shouldComponentUpdate：详见 下方 React.memo.
④render：这是函数组件体本身。
⑤componentDidMount, componentDidUpdate, componentWillUnmount：
useEffect Hook 可以表达所有这些(包括 不那么 常见 的场景)的组合。
⑥componentDidCatch and getDerivedStateFromError：目前还没有这些方法的 Hook 等价写法，但很快会加上。

如何获取上一轮的 props 或 state？
目前，你可以 通过 ref 来手动实现：
function Counter() {
    const [count, setCount] = useState(0);
    const prevCount = usePrevious(count);
    return <h1>Now: {count}, before: {prevCount}</h1>;
  }
  
  function usePrevious(value) {
    const ref = useRef();
    useEffect(() => {
      ref.current = value;
    });
    return ref.current;
}